import { IShaderLayoutInfo, glslup450 } from '@feng3d/glslup';
import { GlslangOptions, GlslangWASM } from './GlslangWASM';
import { TintWASM, TwgslOptions } from './TintWASM';

const tint = new TintWASM();
const glslang = new GlslangWASM();

export interface Options
{
    /**
     * Defines the URL of the glslang JS File.
     */
    glslangJsPath?: string;
    /**
     * Defines the URL of the glslang WASM File.
     */
    glslangWasmPath?: string;

    /**
     * Defines the URL of the twgsl JS File.
     */
    twgslJsPath?: string;
    /**
     * Defines the URL of the twgsl WASM File.
     */
    twgslWasmPath?: string;
}

/**
 * 初始化
 *
 * @param options 设置 glslang 与 twgsl 的js/wasm文件路径。
 *
 * 默认值
 *
 * ```
 * {
    glslangJsPath: `https://preview.babylonjs.com/glslang/glslang.js`,
    glslangWasmPath: `https://preview.babylonjs.com/glslang/glslang.wasm`,
    twgslJsPath: `https://preview.babylonjs.com/twgsl/twgsl.js`,
    twgslWasmPath: `https://preview.babylonjs.com/twgsl/twgsl.wasm`,
}
 * ```
 *
 * 注： 目前只能用于浏览器中。
 *
 * @example
 * ```
 import { glsl2wgsl, initGlsl2wgsl } from '@feng3d/glsl2wgsl';

main();

async function main()
{
    // 初始化
    await initGlsl2wgsl();

    const glslVertex = `
    #version 450

    const vec2 pos[4] = vec2[4](vec2(-1.0f, 1.0f), vec2(1.0f, 1.0f), vec2(-1.0f, -1.0f), vec2(1.0f, -1.0f));
    const vec2 tex[4] = vec2[4](vec2(0.0f, 0.0f), vec2(1.0f, 0.0f), vec2(0.0f, 1.0f), vec2(1.0f, 1.0f));

    layout(location = 0) out vec2 vTex;

    void main() {
        vTex = tex[gl_VertexIndex];
        gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
    }
    `;
    const glslFragment = `
    #version 450

    layout(set = 0, binding = 0) uniform sampler imgSampler;
    layout(set = 0, binding = 1) uniform texture2D img;

    layout(location = 0) in vec2 vTex;
    layout(location = 0) out vec4 outColor;

    void main() {
        outColor = texture(sampler2D(img, imgSampler), vTex);
    }`;

    // 转换顶点着色器
    const wgslVertex = glsl2wgsl(glslVertex, 'vertex');
    // 转换片段着色器
    const wgslFragment = glsl2wgsl(glslFragment, 'fragment');

    console.log(`WebGPU顶点着色器`);
    console.log(wgslVertex);
    console.log(`WebGPU片段着色器`);
    console.log(wgslFragment);
}

 * ```
 */
export async function initGlsl2wgsl(options?: Options)
{
    options = options || {};

    const glslangOptions: GlslangOptions = {};
    if (options.glslangJsPath) glslangOptions.jsPath = options.glslangJsPath;
    if (options.glslangWasmPath) glslangOptions.wasmPath = options.glslangWasmPath;
    await glslang.initGlslang(glslangOptions);

    const twgslOptions: TwgslOptions = {};
    if (options.twgslJsPath) twgslOptions.jsPath = options.twgslJsPath;
    if (options.twgslWasmPath) twgslOptions.wasmPath = options.twgslWasmPath;
    await tint.initTwgsl(twgslOptions);
}

/**
 * glsl转换为wgsl着色器代码。
 *
 * 调用该方法前请先使用 initGlsl2wgsl 函数进行初始化。
 *
 * @param code glsl着色器代码。
 * @param type 代码类型，'vertex' | 'fragment'，默认 'vertex'。
 * @returns 返回转换后的wgsl代码。
 */
export function glsl2wgsl(code: string, layoutInfo?: IShaderLayoutInfo)
{
    const type = isVertexShader(code) ? 'vertex' : 'fragment';

    // 升级为 glsl450
    const glsl450 = glslup450(code, layoutInfo);

    // 转换为 WGSL
    const vertexCode = glslang.compileGLSL(glsl450.code, type);
    const wgsl = tint.convertSpirV2WGSL(vertexCode);

    return { code: wgsl, layoutInfo: glsl450.layoutInfo };
}

function isVertexShader(code: string)
{
    return !!code.match(isVertexShaderReg);
}
const isVertexShaderReg = /\b(gl_Position|gl_VertexIndex|gl_InstanceIndex)\b/g;
